//创建栈类型

import Foundation
struct Stack {
    var items = [Int]()
    
    mutating func push(_ newItem:Int){
        items.append(newItem)
    }
    mutating func pop() -> Int? {
        guard !items.isEmpty else{
            return nil
        }
        return items.removeLast()
    }
}

var intStack = Stack()

intStack.push(1)
intStack.push(2)

print(intStack.pop())
print(intStack.pop())
print(intStack.pop())

//创建一个可以存储任何数据类型的栈
struct Stack2<T> {
    var items = [T]()
    
    mutating func push(_ newItem:T){
        items.append(newItem)
    }
    mutating func pop() -> T? {
        guard !items.isEmpty else{
            return nil
        }
        return items.removeLast()
    }
}

var intStack2 = Stack2<Int>()

intStack2.push(1)
intStack2.push(2)

print(intStack2.pop())
print(intStack2.pop())
print(intStack2.pop())

var strStack = Stack2<String>()

strStack.push("first")
strStack.push("second")

print(strStack.pop())


//泛型函数和方法
func myMap<T,U>(_ items:[T],_ f:(T) -> (U)) -> [U] {
    var result = [U]()
    for item in items {
        result.append(f(item))
    }
    return result
}

let strings = ["one","two","three"]
let stringLengths = myMap(strings) { $0.count }
print(stringLengths)


//类型约束
//指定泛型的约束条件,比如继承于某个类,比如符合一个协议

func checkIfEqual<T:Equatable>(_ first:T,_ second:T) -> Bool {
    return first == second
}

print(checkIfEqual(1, 1))
print(checkIfEqual("a string", "a string"))
print(checkIfEqual("a string", "a different string"))


func checkIfDescriptionsMatch<T:CustomStringConvertible,
                              U:CustomStringConvertible>(_ first:T,_ second:U) -> Bool {
    return first.description == second.description
}

print(checkIfDescriptionsMatch(Int(1), Int(1)))
print(checkIfDescriptionsMatch(1, 1.0))
print(checkIfDescriptionsMatch(Float(1), Float(1.0)))


//关联类型协议
struct StackIterator<T>:IteratorProtocol {
//    typealias Element = T
    var stack:Stack
    
    mutating func next() -> T? {
        return (stack.pop() as! T)
    }
}

var stack2 = Stack()
stack2.push(10)
stack2.push(20)
stack2.push(30)

//var stack2Iterator = StackIterator<Int>(stack: stack2)
//while let value = stack2Iterator.next() {
//    print("获取到值:\(value)")
//}


//深入理解可控类型
//Optional的原理没什么特别的，它只有两个成员的泛型枚举而已
var inta:Int? = 2
switch inta {
case .none:
    print("inta is nil")
case let .some(value):
    print("inta has the value \(value)")
}
